import type { RedisClient } from "./client";

export class SetCommand {
    constructor(client: RedisClient) {
        this.client = client;
    }

    private readonly client: RedisClient;

    // return  the number of elements that were added to the set, not including all the elements already present in the set.
    async sadd(key: string, valueList: string[]): Promise<number> {
        const res = await this.client.exec("SADD", key, ...valueList);
        return res as number;
    }

    // return the cardinality (number of elements) of the set, or 0 if key does not exist.
    async scard(key: string): Promise<number> {
        const res = await this.client.exec("SCARD", key);
        return res as number;
    }

    // return list with members of the resulting set.
    async sdiff(keyList: string[]): Promise<string[]> {
        const res = await this.client.exec("SDIFF", ...keyList);
        return res as string[];
    }

    // return the number of elements in the resulting set.
    async sdiffStore(destkey: string, keyList: string[]): Promise<number> {
        const res = await this.client.exec("SDIFFSTORE", destkey, ...keyList);
        return res as number;
    }

    // return  list with members of the resulting set.
    async sinter(keyList: string[]): Promise<string[]> {
        const res = await this.client.exec("SINTER", ...keyList);
        return res as string[];
    }

    // return the number of elements in the resulting intersection.
    async sinterCard(numkeys: number, keyList: string[], limit: number = 0): Promise<number> {
        const args = ["SINTERCARD", numkeys.toFixed(0), ...keyList];
        if (limit > 0) {
            args.push("LIMIT", limit.toFixed());
        }
        const res = await this.client.exec(...args);
        return res as number;
    }

    // return the number of elements in the resulting set.
    async sinterStore(destkey: string, keyList: string[]): Promise<number> {
        const res = await this.client.exec("SINTERSTORE", destkey, ...keyList);
        return res as number;
    }

    // return 1 if the element is a member of the set,0 for not
    async sismember(key: string, value: string): Promise<number> {
        const res = await this.client.exec("SISMEMBER", key, value);
        return res as number;
    }

    // return all elements of the set.
    async smembers(key: string): Promise<string[]> {
        const res = await this.client.exec("SMEMBERS", key);
        return res as string[];
    }

    // return list representing the membership of the given elements, in the same order as they are requested.
    async smismember(key: string, valueList: string[]): Promise<number[]> {
        const res = await this.client.exec("SMISMEMBER", key, ...valueList);
        return res as number[];
    }

    // return 1 if the element is moved. 0 for not
    async smove(key: string, destKey: string, value: string): Promise<number> {
        const res = await this.client.exec("SMOVE", key, destKey, value);
        return res as number;
    }

    async spop(key: string, count: number = 0): Promise<unknown> {
        const args = ["SPOP", key];
        if (count > 0) {
            args.push(count.toFixed(0));
        }
        const res = await this.client.exec(...args);
        return res;
    }

    async srandmember(key: string, count: number = 0): Promise<unknown> {
        const args = ["SRANDMEMBER", key];
        if (count > 0) {
            args.push(count.toFixed(0));
        }
        const res = await this.client.exec(...args);
        return res;
    }

    // return the number of members that were removed from the set, not including non existing members.
    async srem(key: string, valueList: string[]): Promise<number> {
        const res = await this.client.exec("SREM", key, ...valueList);
        return res as number;
    }

    async sscan(key: string, cursor: number, pattern: string = "", count: number = 0): Promise<unknown> {
        const args = ["SSCAN", key, cursor.toFixed(0)];
        if (pattern !== "") {
            args.push("MATCH", pattern);
        }
        if (count > 0) {
            args.push("COUNT", count.toFixed(0));
        }
        const res = this.client.exec(...args);
        return res;
    }

    // return list with members of the resulting set.
    async sunion(keyList: string[]): Promise<string[]> {
        const res = await this.client.exec("SUNION", ...keyList);
        return res as string[];
    }

    // return the number of elements in the resulting set.
    async sunionStore(destKey: string, keyList: string[]): Promise<number> {
        const res = await this.client.exec("SUNIONSTORE", destKey, ...keyList);
        return res as number;
    }
}